<script setup>import { ref, onMounted, watch, computed } from 'vue'
import { useExportChart } from './hooks/useExportChart'
import { useZoom } from './hooks/useZoom'
import { useTreeData } from './hooks/useTreeData'
import { useMeterStore } from '@/stores/meter'
import * as d3 from 'd3'
import { storeToRefs } from 'pinia'
import waterMeterIcon from '@/assets/icon/物联网水表.png'

// 接收props
const props = defineProps({
    meterList: {
        type: Array,
        default: () => []
    },
    treeData: {
        type: Array,
        default: () => []
    }
});

const svgRef = ref(null)
const meterStore = useMeterStore()
const { treeDataForChart } = storeToRefs(meterStore)
const { exportChart } = useExportChart(svgRef)
const { zoom, initZoom, zoomIn, zoomOut } = useZoom(svgRef)
const { processTreeData } = useTreeData()
const loading = ref(true)

// 获取要使用的树形数据
const treeDataToUse = computed(() => {
    return props.treeData.length > 0 ? props.treeData : treeDataForChart.value;
});

const currentType = computed(() => {
    return treeDataToUse.value.length > 0 ? treeDataToUse.value[0].type : null;
})

const clearSvg = () => {
    if (!svgRef.value) return
    const container = d3.select(svgRef.value)
    container.selectAll('*').remove()
}

const renderNodes = (svg, node) => {
    const group = svg.append("g")
        .attr("transform", `translate(${node.x},${node.y})`)

    if (currentType.value === 1) {
        group.append("image")
            .attr("href", waterMeterIcon)
            .attr("x", -15)
            .attr("y", -15)
            .attr("width", 40)
            .attr("height", 40)

        const textGroup = group.append("g")
            .attr("transform", "translate(40, -20)")

        textGroup.append("text")
            .attr("font-size", "13px")
            .attr("font-family", "'SimSun', '宋体', serif")
            .attr("fill", "#333")
            .attr("text-anchor", "start")
            .text(node.label)

        if (node.spec) {
            textGroup.append("text")
                .attr("transform", "translate(0, 20)")
                .attr("font-size", "13px")
                .attr("font-family", "'SimSun', '宋体', serif")
                .attr("fill", "#333")
                .attr("text-anchor", "start")
                .text(node.spec)
        }

        if (node.supply_region) {
            const maxWidth = 120
            const boxWidth = Math.min(node.supply_region.length * 14 + 20, maxWidth)

            group.append("rect")
                .attr("x", -boxWidth / 2)
                .attr("y", 35)
                .attr("width", boxWidth)
                .attr("height", 24)
                .attr("fill", "white")
                .attr("stroke", "#666")
                .attr("stroke-width", 1)
                .attr("rx", 2)

            group.append("text")
                .attr("text-anchor", "middle")
                .attr("font-size", "12px")
                .attr("fill", "#333")
                .attr("transform", `translate(0, 50)`)
                .text(node.supply_region)
        }
    } else {
        group.append("g")
            .html(` 
        <line x1="-10" y1="-5" x2="-10" y2="5" stroke="#333" stroke-width="1.5" />
        <line x1="-10" y1="0" x2="10" y2="0" stroke="#333" stroke-width="1.5" />
        <line x1="10" y1="-5" x2="10" y2="5" stroke="#333" stroke-width="1.5" />
        <circle cx="0" cy="15" r="8" fill="none" stroke="#333" stroke-width="1.5" />
        <path d="M -8,25 C -5,22 5,22 8,25" stroke="#333" fill="none" stroke-width="1.2" />
        <path d="M -6,22 C -3,19 3,19 6,22" stroke="#333" fill="none" stroke-width="1.2" />
        <path d="M -4,19 C -2,16 2,16 4,19" stroke="#333" fill="none" stroke-width="1.2" />
      `)

        const textGroup = group.append("g")
            .attr("transform", "translate(0, -10)")

        textGroup.append("text")
            .attr("font-size", "13px")
            .attr("font-family", "'SimSun', '宋体', serif")
            .attr("fill", "#333")
            .attr("text-anchor", "middle")
            .text(node.label)

        if (node.spec) {
            textGroup.append("text")
                .attr("transform", "translate(0, 20)")
                .attr("font-size", "13px")
                .attr("font-family", "'SimSun', '宋体', serif")
                .attr("fill", "#333")
                .attr("text-anchor", "middle")
                .text(node.spec)
        }

        if (node.supply_region) {
            const maxWidth = 120
            const boxWidth = Math.min(node.supply_region.length * 14 + 20, maxWidth)

            group.append("rect")
                .attr("x", -boxWidth / 2)
                .attr("y", 35)
                .attr("width", boxWidth)
                .attr("height", 24)
                .attr("fill", "white")
                .attr("stroke", "#666")
                .attr("stroke-width", 1)
                .attr("rx", 2)

            group.append("text")
                .attr("text-anchor", "middle")
                .attr("font-size", "12px")
                .attr("fill", "#333")
                .attr("transform", `translate(0, 50)`)
                .text(node.supply_region)
        }
    }

    if (node.children) {
        node.children.forEach(child => renderNodes(svg, child))
    }
}

const initVisualization = async () => {
    loading.value = true
    clearSvg()

    const rawData = treeDataToUse.value
    const treeData = processTreeData(rawData)

    const container = d3.select(svgRef.value)
        .attr("width", "100%")
        .attr("height", "800")
        .attr("viewBox", "0 0 1200 800")
        .attr("preserveAspectRatio", "xMidYMid meet")

    container.append("rect")
        .attr("width", "100%")
        .attr("height", "100%")
        .attr("fill", "white")

    const svg = container.append("g")
        .attr("class", "zoom-group")

    const renderLinks = (node) => {
        if (!node.children) return

        node.children.forEach(child => {
            svg.append("path")
                .attr("d", `M ${node.x} ${node.y + 30} L ${node.x} ${(node.y + child.y) / 2} L ${child.x} ${(node.y + child.y) / 2} L ${child.x} ${child.y - 20}`)
                .attr("stroke", "#666")
                .attr("fill", "none")
                .attr("stroke-width", 1.5)

            renderLinks(child)
        })
    }

    treeData.forEach(node => {
        renderLinks(node)
        renderNodes(svg, node)
    })

    const bbox = svg.node().getBBox()
    const padding = 50
    const scale = Math.min(
        1200 / (bbox.width + padding * 2),
        800 / (bbox.height + padding * 2)
    )
    const transform = d3.zoomIdentity
        .translate(
            (1200 - bbox.width * scale) / 2 - bbox.x * scale,
            (800 - bbox.height * scale) / 2 - bbox.y * scale
        )
        .scale(scale)

    initZoom()
    container.call(zoom.value.transform, transform)
    loading.value = false
}

watch(() => treeDataToUse.value, (newData) => {
    if (newData) {
        initVisualization()
    }
}, { immediate: true })

onMounted(async () => {
    initZoom()
    initVisualization()
})
</script>

<template>
    <div class="svg-container" v-loading="loading">
        <div class="controls">
            <el-button @click="zoomOut">
                <template #icon>
                    <i class="fa fa-search-minus"></i>
                </template>
            </el-button>
            <el-button @click="zoomIn">
                <template #icon>
                    <i class="fa fa-search-plus"></i>
                </template>
            </el-button>
            <el-button @click="exportChart">
                <template #icon>
                    <i class="fa fa-download"></i>
                </template>
            </el-button>
        </div>

        <svg ref="svgRef" class="cursor-move"></svg>
    </div>
</template>

<style scoped>
.controls {
    margin-top: 1rem;
}

.svg-container {
    position: relative;
    width: 100%;
    height: 100%;
}

svg {
    width: 100%;
    height: 100%;
    display: block;
}
</style>
